SQL Injection

手工注入

注入思路

数据库注入主要有如下方法:

UNION query SQL injection(可联合查询注入)
Stacked queries SQL injection(可多语句查询注入)
Boolean-based blind SQL injection(布尔型注入)
Error-based SQL injection(报错型注入)
Time-based blind SQL injection(基于时间延迟注入)

下面主要结合dvwa来介绍下可联合查询注入

注入思路主要如下

  1. 判断是否存在注入点

  2. 获取当前数据库名(利用database()函数)

  3. 利用information_schema的tables表获取当前数据库表的表名信息

  4. 利用information_schema的columns获取表的字段名信息

  5. 获取表中的信息

dvwa练习

  1. LOW

    SQL Injection4

    正常输入数字,观察下返回结果。基本上可以明白是输入ID来查询用户名的操作。

    输入1‘后返回错误提示信息,由此判断存在注入

    SQL Injection5

    然后输入1 or 1 = 1,返回结果和输入1没有区别

    SQL Injection6

    再输入 1‘ or ‘1’ = ‘1,成功得到了所有的信息,所以可以判断出是字符型注入

    SQL Injection7

    下面来直接尝试下能否利用database()函数获取数据库名

    SQL Injection8

    可以发现成功的获得了数据库名,有了数据库名后,就尝试是否有权限访问information_schema数据库中的表,来尽可能多的获取当前数据库的信息(所以设置好相应的权限也是防注入的重要方法吧)构造SQL可以开个记事本之类的来用防止写错也好修改,就不要在web上直接输入

    1’ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

    SQL Injection9

    从上面的结果可以看到成功的获得了表名,再利用information_schema这个数据查看下每张表中有哪些字段

    1’ union select 1,group_concat(column_name) from information_schema.columns where table_name = ‘guestbook’ #

    SQL Injection10

    SQL Injection11

    可以看到成功的获得了每张表对应的字段名。现在来获取user和password

    1’ union select user,password from users #SQL Injection12

    这样我们就获得了用户名和对应的密码哈希值。可以去在线的哈希破解网站跑一下,弱口令一般都可以免费跑出来(下图就是admin对应哈希密码跑出来的结果),通过上面一顿操作我们就拿到了所有的用户名和密码!SQL Injection13

  1. MEDIUM

    SQL Injection14

    可以看到中等难度是下拉框形式,没法输入

    SQL Injection15

    提交试了一下,发现也是输入ID返回用户名,提交方式是post,所以只有截取数据包进行修改了

    SQL Injection16

    打开burp设置好代理,浏览器也设好相应的代理

    SQL Injection17

    可以看到捕获到的包的body携带了提交的信息,在这里进行如low等级的尝试

    SQL Injection18

    SQL Injection19

    可以看到成功的执行了,所以这里是数字型注入

    同理我们来尝试下能不能获取数据库名

    SQL Injection20

    可以看到成功的获取到了数据库名还是,dvwa

    继续看下能否利用information_schema来获取这个数据库的信息

    SQL Injection21

    OK这里也成功获取到了表名,guestbook,users

    下面继续利用information_schema来获取表中字段信息

    SQL Injection22

    然后发现这里gg了…还好这里有返回信息,我们可以发现输入的单引号被转义成了\,这里对方加入了特殊字符转义来防注入,这里我们用16进制来绕过

    users查下ascii表得到0x7573657273SQL Injection23

    Ok,可以发现我们成功的得到了表的字段信息下面来获取user和password

    SQL Injection24

    成功,medium等级主要需要一个截包修改body和处理转义问题

  2. HARD

    image-20190331163042873

    可以看到High等级是弹窗后让输入查询。然后开始测试

    SQL Injection25

    SQL Injection26

    发现无论是字符还是数字返回的都只有一条信息,推测有limit限制

    image-20190331163503654

    测试后发现字符型注入成功,

    继续试能不能获得数据库名

    image-20190331163705814

    成功获取到数据库名,dvwa

    继续看能否利用informatiuon_schema库获取当前数据库信息

    image-20190331163940458

    又成功获取到表名,guestbook,users,继续看能否获取到users信息

    image-20190331164300901

    好吧又成功获取到了表的字段名

    开始输入时少输入了一个#,结果弹出了下面的窗口

    image-20190331165915338

    无论怎么刷新或重新登陆弹出的窗口依旧是上面的,清除cookie后才恢复正常

    image-20190331170140167

    然后就成功的得到了用户名密码

    image-20190331170821604

    所以high等级依旧主要加如了一个limit可以通过注视绕过,以及错误后阻止操作,通过清理cookie解决了所以用匿名窗口就方便很多,关了重开就是了

  3. IMPOSSIBLE

    测试了下发现只有正常查询的时候回返回结果,结果返回与数量不一致时不会返回任何结果

    采用了所谓的PDO技术,OK这个技术在后面我会去学习下再来解释,顺便看下PHP,学习下PHP的审计

    毕竟是是世界最好的语言

tips(主要都是些SQL语法):

  1. mysql中的注释方法:

    1. “– “,**注意–后面有一个空格

    2. /* */

      这里的注释符号可以帮我去注释掉字符注入中后面的 ‘,这样可以让我们去执行order by这些操作

  2. order by num:

    order by是SQL语句中用于指定排序的,一般接的是列名,但也可以用数字,比如order by 1就表示已第一列为排序标准,默认升序排序,这避免了我们不知道列名

    通过这样的尝试我们也能获取到数据表的列数

  3. select除了查询的功能

    1. 插入功能

      很神奇,原来select还可以插入(或者说复制表),一直以为是查询用的…

      select into from 和 insert into select都是用来复制表,两者的主要区别为:

      select into from 要求目标表不存在,因为在插入时会自动创建。

      insert into select from 要求目标表存在

    2. select 1,2…

      这个主要配合union使用,union select 1,2,3..

      主要用于SQL注入时,去判断字段顺序

      这里1,2,3…的个数要和前面union的表列数一致,这样才能拼接

      这样能配合前面显示的数据来判断,前面数据的字段顺序

      union_select

      如上图所示在我们注入的时候输入的是 1 union select 1,2

      返回结果我们就可以根据1,2对应的位置判断出1,test1,它们对应的先后顺序

      也有用user(),version(),database(),loadfile()…这些方法来获取信息

      union_select2

      最后我们知道一些表的表名还可以通过这样的方式来试探那张表中的信息

      SQL Injection3

      如上图所示。这里我们假设知道有一张pwd的表,然后猜测有字段user,password这样的字段(猜不到的就和上面一样用数字来代替),这样我们就可以获取到一些信息了(当然正常密码都不会已明文存储…可以去一些在线破hash的网站尝试一下)

  4. information_schema

    MySQL系统自带的数据库有个information_schema数据库,里面有张名tables的表

    里面有存放所有数据库的表信息

    select group_concat(table_name) from information_schema.tables where table_schema=database()

    通过上面的SQL语句就可以查出当前数据库中所有表的名称

    知道表名称后通过下面的SQL语句又可以求出表中的列名

    select group_concat(column_name) from information_schema.columns where table_name=’tablename’

  5. concat(),concat_ws(),group_concat()

  6. 要用当前数据库名的时候尽量直接用database(),不要写database()查出来的数据库名,有些地方会转义单引号这些,而直接写database()不会被影响

  7. 遇到字符转义通过改写16进制绕过

总结

基本上是刚接触web安全,有很多地方可能自己理解也不是很到位,欢迎一起沟通交流。

这次主要结合dvwa的SQL注入来进行的一个初浅的web安全学习,后面会继续完成dvwa的盲注,sqlmap等的工具应用,和继续深入的学习sql的注入以及别的web安全知识

这次sql注入确实也学习了很多,比如很多sql语句自己以前学习Django调用数据库时都是没有用过的,还有大佬为我演示过利用sql语句来上传网马等的操作,确实对数据库的了解还是太初浅了。也通过本次学习sql注入也思考了很多关于如何预防注入的方法,比如设置好权限,对于用户的查询权限就设置好,定到具体的数据库以及表,限制用户的输入,对输入进行严格的判断等…

参考

  1. 新手指南:DVWA-1.9全级别教程之SQL Injection
  2. DVWA SQL Injection 通关教程


路漫漫其修远兮,吾将上下而求索